/*
 * Copyright 2002-2006 the original author or authors. Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language governing permissions and limitations under the
 * License.
 */
package org.springframework.samples.countries.web;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

import net.sourceforge.jwebunit.junit.WebTester;
import net.sourceforge.jwebunit.util.TestContext;
import net.sourceforge.jwebunit.util.TestingEngineRegistry;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;

public class PagesTestCase {

	private static org.mortbay.jetty.Server server = null;

	private final static int PORT = 8089;

	private final static String DOMAIN = "localhost";

	private final static String ROOT_CONTEXT = "/countries";

	private final static String BASE_URL = "http://" + DOMAIN + ":" + Integer.toString(PORT) + ROOT_CONTEXT;

	private final static TestContext TEST_CONTEXT = new TestContext();
	
	private WebTester browser = null;

	@BeforeClass
	public static void startServer() throws Exception {
		server = new org.mortbay.jetty.Server(PORT);
		server.addHandler(new org.mortbay.jetty.webapp.WebAppContext("src/main/webapp", ROOT_CONTEXT));
		server.start();
		
		TEST_CONTEXT.setBaseUrl(BASE_URL);
		TEST_CONTEXT.setLocale(Locale.US);
	}

	@AfterClass
	public static void stopServer() throws Exception {
		server.stop();
	}

	@Before
	public void createWebTester() {
		browser = new WebTester();
		browser.setTestingEngineKey(TestingEngineRegistry.TESTING_ENGINE_HTMLUNIT);
		
		browser.setTestContext(TEST_CONTEXT);
	}

	@Test
	public void visitHomePage() throws Exception {
		browser.beginAt("/home.htm");

		Assert.assertEquals(getTestHtml("home.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageInBlue() throws Exception {
		browser.beginAt("/home.htm?theme=blue");

		Assert.assertEquals(getTestHtml("homeBlue.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageInBlueFromFrance() throws Exception {
		browser.beginAt("/home.htm?theme=blue&locale=fr_FR");

		Assert.assertEquals(getTestHtml("homeBlueFrench.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageInBlueFromGermany() throws Exception {
		browser.beginAt("/home.htm?theme=blue&locale=de_DE");

		Assert.assertEquals(getTestHtml("homeBlueGerman.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromUSA() throws Exception {
		browser.beginAt("/home.htm?locale=en_US");
		Assert.assertEquals(getTestHtml("homeEnglish.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromFrance() throws Exception {
		browser.beginAt("/home.htm?locale=fr_FR");
		Assert.assertEquals(getTestHtml("homeFrench.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromGermany() throws Exception {
		browser.beginAt("/home.htm?locale=de_DE");
		Assert.assertEquals(getTestHtml("homeGerman.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromFranceWithNoneTheme() throws Exception {
		browser.beginAt("/home.htm?locale=fr_FR&theme=none");
		Assert.assertEquals(getTestHtml("homeNoneFrench.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromGermanyWithNoneTheme() throws Exception {
		browser.beginAt("/home.htm?locale=de_DE&theme=none");
		Assert.assertEquals(getTestHtml("homeNoneGerman.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageWithNoneTheme() throws Exception {
		browser.beginAt("/home.htm?theme=none");
		Assert.assertEquals(getTestHtml("homeNoTheme.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageWithSpringTheme() throws Exception {
		browser.beginAt("/home.htm?theme=spring");
		Assert.assertEquals(getTestHtml("homeSpring.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromFranceWithSpringTheme() throws Exception {
		browser.beginAt("/home.htm?locale=fr_FR&theme=spring");
		Assert.assertEquals(getTestHtml("homeSpringFrench.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromGermanyWithSpringTheme() throws Exception {
		browser.beginAt("/home.htm?locale=de_DE&theme=spring");
		Assert.assertEquals(getTestHtml("homeSpringGerman.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageWithWhiteTheme() throws Exception {
		browser.beginAt("/home.htm?theme=white");
		Assert.assertEquals(getTestHtml("homeWhite.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromFranceWithWhiteTheme() throws Exception {
		browser.beginAt("/home.htm?locale=fr_FR&theme=white");
		Assert.assertEquals(getTestHtml("homeWhiteFrench.htm"), browser.getPageSource());
	}

	@Test
	public void visitHomePageFromGermanyWithWhiteTheme() throws Exception {
		browser.beginAt("/home.htm?locale=de_DE&theme=white");
		Assert.assertEquals(getTestHtml("homeWhiteGerman.htm"), browser.getPageSource());
	}

	@Test
	public void visitConfigPage() throws Exception {
		browser.beginAt("/config.htm");

		Assert.assertEquals(getTestHtml("config.htm"), browser.getPageSource());
	}

	@Test
	public void visitConfigPageFromGermanyWithBlue() throws Exception {
		browser.beginAt("/config.htm?locale=de_DE&theme=blue");

		Assert.assertEquals(getTestHtml("configBlueGerman.htm"), browser.getPageSource());
	}

	@Test
	public void visitConfigPageFromFrance() throws Exception {
		browser.beginAt("/config.htm?locale=fr_FR");

		Assert.assertEquals(getTestHtml("configFrench.htm"), browser.getPageSource());
	}

	@Test
	public void visitConfigPageFromGermany() throws Exception {
		browser.beginAt("/config.htm?locale=de_DE");

		Assert.assertEquals(getTestHtml("configGerman.htm"), browser.getPageSource());
	}

	@Test
	public void visitNonExistingPage() throws Exception {

		browser.beginAt("/notfound.htm");
		Assert.assertEquals(getTestHtml("notFound.htm"), browser.getPageSource());

	}

	@Test
	public void visitNonExistingPage1() throws Exception {

		browser.beginAt("/notfound.htm");
		Assert.assertEquals(getTestHtml("notFound.htm"), browser.getPageSource());

	}

	@Test
	public void visitMainPage() throws Exception {
		browser.beginAt("/main/home.htm");

		Assert.assertEquals(filterForMainPage(getTestHtml("mainHome.htm")),
				filterForMainPage(browser.getPageSource()));
	}

	@Test
	public void visitMainPageFirstPage() throws Exception {
		browser.beginAt("/main/home.htm?page=0");

		Assert.assertEquals(filterForMainPage(getTestHtml("mainHome.htm")),
				filterForMainPage(browser.getPageSource()));
	}

	@Test
	public void visitMainPageSecondPage() throws Exception {
		browser.beginAt("/main/home.htm?page=1");

		Assert.assertEquals(filterForMainPage(getTestHtml("mainHomePage2.htm")), filterForMainPage(browser
				.getPageSource()));
	}

	@Test
	public void visitMainPageLastPage() throws Exception {
		browser.beginAt("/main/home.htm?page=24");

		Assert.assertEquals(filterForMainPage(getTestHtml("mainHomePage24.htm")), filterForMainPage(browser
				.getPageSource()));
	}

	@Test
	public void visitDetailPageAG() throws Exception {
		browser.beginAt("/main/detail.htm?code=AG");

		Assert.assertEquals(getTestHtml("detailAG.htm"), browser.getPageSource());
	}

	@Test
	public void visitDetailPageAGFrench() throws Exception {
		browser.beginAt("/main/detail.htm?code=AG&locale=fr_FR");

		Assert.assertEquals(getTestHtml("detailAGFrench.htm"), browser.getPageSource());
	}

	@Test
	public void visitDetailPageAN() throws Exception {
		browser.beginAt("/main/detail.htm?code=AN");

		Assert.assertEquals(getTestHtml("detailAN.htm"), browser.getPageSource());
	}

	@Test
	public void visitMainPageFromFrance() throws Exception {
		browser.beginAt("/main/home.htm?locale=fr_FR");

		Assert.assertEquals(filterForMainPage(getTestHtml("mainHomeFromFrance.htm")), filterForMainPage(browser
				.getPageSource()));
	}

	@Test
	public void visitMainPageFromGermany() throws Exception {
		browser.beginAt("/main/home.htm?locale=de_DE");

		Assert.assertEquals(filterForMainPage(getTestHtml("mainHomeFromGermany.htm")), filterForMainPage(browser
				.getPageSource()));
	}

	@Test @Ignore
	public void sortMainPageByName() throws Exception {
		browser.beginAt("/main/home.htm?sort.property=name");
		Assert.assertEquals(filterForMainPage(getTestHtml("sortMainPageByName1.htm")), filterForMainPage(browser
				.getPageSource()));
		browser
				.clickElementByXPath("/html/body/div[@id='pageContent']/div[@id='inContent']/div[@id='content']/form/table/thead/tr[1]/th/a[@href='/countries/main/home.htm?sort.property=name']");
		Assert.assertEquals(filterForMainPage(getTestHtml("sortMainPageByName2.htm")), filterForMainPage(browser
				.getPageSource()));
	}

	@Test
	public void sortMainPageByCode() throws Exception {
		browser.beginAt("/main/home.htm?sort.property=code");
		Assert.assertEquals(filterForMainPage(getTestHtml("sortMainPageByCode1.htm")), filterForMainPage(browser
				.getPageSource()));
		browser
				.clickElementByXPath("/html/body/div[@id='pageContent']/div[@id='inContent']/div[@id='content']/form/table/thead/tr[1]/th[2]/a[@href='/countries/main/home.htm?sort.property=code']");
		Assert.assertEquals(filterForMainPage(getTestHtml("sortMainPageByCode2.htm")), filterForMainPage(browser
				.getPageSource()));
		browser
				.clickElementByXPath("/html/body/div[@id='pageContent']/div[@id='inContent']/div[@id='content']/form/table/thead/tr[1]/th[2]/a[@href='/countries/main/home.htm?sort.property=code']");
		Assert.assertEquals(filterForMainPage(getTestHtml("sortMainPageByCode3.htm")), filterForMainPage(browser
				.getPageSource()));
	}

	@Test @Ignore
	public void changePageSize5() throws Exception {
		browser.beginAt("/main/home.htm");
		String[] options = new String[7];
		options[0] = "5 rows/page";
		options[1] = "10 rows/page";
		options[2] = "15 rows/page";
		options[3] = "20 rows/page";
		options[4] = "30 rows/page";
		options[5] = "40 rows/page";
		options[6] = "80 rows/page";
		browser.assertSelectOptionsPresent("pageSize", options);
		browser.assertSelectedOptionEquals("pageSize", "10 rows/page");
		browser.selectOption("pageSize", "5 rows/page");
		browser.assertSelectedOptionEquals("pageSize", "5 rows/page");
		Assert.assertEquals(filterForMainPage(getTestHtml("selectPageSize5.htm")), filterForMainPage(browser
				.getPageSource()));
	}

	@Test @Ignore
	public void changePageSize80() throws Exception {
		browser.beginAt("/main/home.htm");
		String[] options = new String[7];
		options[0] = "5 rows/page";
		options[1] = "10 rows/page";
		options[2] = "15 rows/page";
		options[3] = "20 rows/page";
		options[4] = "30 rows/page";
		options[5] = "40 rows/page";
		options[6] = "80 rows/page";
		browser.assertSelectOptionsPresent("pageSize", options);
		browser.assertSelectedOptionEquals("pageSize", "10 rows/page");
		browser.selectOption("pageSize", "80 rows/page");
		browser.assertSelectedOptionEquals("pageSize", "80 rows/page");
		Assert.assertEquals(filterForMainPage(getTestHtml("selectPageSize80.htm")), filterForMainPage(browser
				.getPageSource()));
	}

	@Test
	@Ignore
	public void filterByCode() throws Exception {
		browser.beginAt("/main/home.htm");
		StringTokenizer tokenizer = new StringTokenizer("A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,W,X,Y,Z", ",");
		List<String> letters = new LinkedList<String>();
		while (tokenizer.hasMoreTokens()) {
			String nextToken = tokenizer.nextToken();
			letters.add(nextToken);
		}

		String[] options = letters.toArray(new String[0]);
		browser.assertSelectOptionsPresent("filter.code", options);
		browser.assertSelectedOptionEquals("filter.code", "");
		browser.selectOption("filter.code", "D");
		browser.assertSelectedOptionEquals("filter.code", "D");
		Assert.assertEquals(filterForMainPage(getTestHtml("selectCodeD.htm")), filterForMainPage(browser
				.getPageSource()));
		// webtester.selectOption("filter.code", "E");
		// Assert.assertEquals(filterForMainPage(getTestHtml("selectCodeD.htm")),filterForMainPage(webtester.getPageSource()));
	}

	public String filterForMainPage(String source) throws IOException {
		StringBuffer buffer = new StringBuffer();

		BufferedReader reader = new BufferedReader(new StringReader(source));
		String line = reader.readLine();

		while (line != null) {
			if (line.contains("currentDate")) {
				buffer.append(line);
				line = reader.readLine();
				if (line != null) {
					buffer.append('\n');
				}
				line = reader.readLine();
			}
			else {
				buffer.append(line);
				line = reader.readLine();
				if (line != null) {
					buffer.append('\n');
				}
			}
		}
		reader.close();
		return buffer.toString();
	}

	public String getTestHtml(String fileName) throws IOException {

		StringBuffer buffer = new StringBuffer();

		BufferedReader reader = new BufferedReader(new InputStreamReader(this.getClass().getClassLoader()
				.getResourceAsStream(fileName),"ISO-8859-1"));
		String line = reader.readLine();

		while (line != null) {
			buffer.append(line);
			line = reader.readLine();
			if (line != null) {
				buffer.append('\n');
			}
		}
		reader.close();
		return buffer.toString();
	}
}
